#include "VerifyGrpcClient.h"
#include "ConfigMgr.h"

GetVarifyRsp VerifyGrpcClient::GetVarifyCode(std::string email)
{
	ClientContext context;
	GetVarifyRsp reply;
	GetVarifyReq request;
	request.set_email(email);
	std::unique_ptr<message::VarifyService::Stub> stub = _pool->getConnection();
	Status status = stub->GetVarifyCode(&context, request, &reply);
	if (status.ok())
	{
		_pool->returnConnection(std::move(stub));
		return reply;
	}
	else
	{
		_pool->returnConnection(std::move(stub));
		reply.set_error(ErrorCodes::RPCFailed);
		return reply;
	}
}

VerifyGrpcClient::VerifyGrpcClient()
{
	auto& gCfgMgr = ConfigMgr::Inst();
	std::string host = gCfgMgr["VarifyServer"]["host"];
	std::string port = gCfgMgr["VarifyServer"]["port"];
	_pool.reset(new RPConRool(5, host, port));
}

RPConRool::RPConRool(std::size_t poolsize, std::string host, std::string port)
	:_poolSize(poolsize)
	, _host(host)
	, _port(port)
{
	std::shared_ptr<Channel> channel = grpc::CreateChannel(host + ":" + port,
		grpc::InsecureChannelCredentials());
	_connections.push(VarifyService::NewStub(channel));
}

RPConRool::~RPConRool()
{
	std::lock_guard<std::mutex> lock(_mutex);
	Close();
	while (!_connections.empty())
	{
		_connections.pop();
	}
}

void RPConRool::Close()
{
	_b_stop = true;
	_cond.notify_all();
}

std::unique_ptr<VarifyService::Stub> RPConRool::getConnection()
{
	std::unique_lock<std::mutex> lock(_mutex);
	_cond.wait(lock, [this]() {
		if (_b_stop)
		{
			return true;
		}
		return !_connections.empty();
		});
	if (_b_stop)
	{
		return nullptr;
	}
	auto context = std::move(_connections.front());
	_connections.pop();
	return context;
}

void RPConRool::returnConnection(std::unique_ptr<VarifyService::Stub> context)
{
	std::lock_guard<std::mutex> lock(_mutex);
	if (_b_stop)
	{
		return;
	}
	_connections.push(std::move(context));
	_cond.notify_one();
}